package com.gao.service.impl;

import com.gao.dao.GoodsMapper;
import com.gao.domain.Goods;
import com.gao.service.IGoodsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author gao
 * @time 2020/04/2020/4/24 22:12:42
 */

@Service
@Transactional
public class GoodsServiceImpl implements IGoodsService {

    @Autowired
    private GoodsMapper mapper;

    // 悲观锁
    @Override
    public boolean updateGoodsAmount(Integer gid, Integer amount) {
        synchronized (this) {
            Goods goods = mapper.findByGid(gid);
            Integer stock = goods.getStock();
            if (stock < amount) {
                return false;
            }
            try {
                mapper.deductStock(gid, amount);
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
        return true;
    }

    // 乐观锁，这里必须将事务的隔离级别设置为 read committed
    // 否则，线程A读取到一个version（0），另一个线程B修改了version（1），再被另外一个线程
    @Transactional(isolation = Isolation.READ_COMMITTED)
    @Override
    public boolean updateGoodsAmountByVersion(Integer gid, Integer amount) {
        // System.out.println(Thread.currentThread().getName() + " start ");
        while (true) {
            Goods goods = mapper.findByGid(gid);
            Integer stock = goods.getStock();
            if (stock < amount) {
                return false;
            }
            try {
                int rows = mapper.deductStockByVersion(gid, amount, goods.getVersion());
                // System.out.println(Thread.currentThread().getName() + "  version：" + goods.getVersion() + "，stock：" + stock + "，rows：" + rows);
                // Thread.sleep(3000);
                if (rows > 0) {
                    return true;
                }
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
            // 如果更新失败，就让当前线程休眠一段时间，削峰（防止cpu占用过高）。
            try {
                Thread.sleep(10);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

    @Override
    public void delete(Integer gid) {
        mapper.delete(gid);
    }

    @Override
    public void save(Goods goods) {
        mapper.save(goods);
    }

    @Override
    public Goods findByGid(Integer gid) {
        return mapper.findByGid(gid);
    }
}
